#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include "los_base.h"
#include "los_swtmr.h"
#include "los_mux.h"
#include "message_flow.h"
#include "ext_node_func.h"
#include "point_read_write.h"
#include "bsp_api.h"
#include "modbus.h"
#include "read_and_write_flash.h"
#include "main.h"
#include "omip_log.h"

extern uint8_t g_mode; //主设备还是从设备模式 
static UINT32	motor_task_id;

typedef struct input_arg //input
{
    node_output_t 	  * output;
    flow_node_base_t  * node;
    UINT16 				timer_id;
    struct input_arg  * next;
    char 				attr_type[IO_ATTR_TYPE_MAX_LEN];
    char 				sensor_type[IO_ATTR_SENSOR_TYPE_MAX_LEN];
    char 				node_id[NODE_ID_MAX_LEN];
    int 				obj_id;
}input_arg_t;

typedef struct output_arg //output
{
    struct output_arg * next;
	UINT16				timer_id;
    int					obj_id;
    char				node_id[NODE_ID_MAX_LEN];
	int 				cnt; //判断output节点是否有连线,cnt=0:no connnet wires cnt>0:connect wires
} output_arg_t;

static input_arg_t 	* g_input_arg_list =NULL;
static output_arg_t * g_output_arg_list=NULL;

static void input_callback(UINT32 arg)
{
    struct input_arg *temp =(struct input_arg *)arg;
    point_data_t *point = vav_get_point_by_id(temp->obj_id);
    if(point->max_priority < 16)
    {
        temp->output->poutput_wires[0]->usout_data = point->priority_arr[point->max_priority-1].value;
        g_node_func_add_queue_callback_pf(temp->node, temp->output);
		OMIP_LOG_INFO( "max_priority:%d, acnode_id:%s stype:%s usout_data:%d", 
			point->max_priority, temp->node->acnode_id, temp->sensor_type, (int)(temp->output->poutput_wires[0]->usout_data));
        return;
    }
    if(strcmp(temp->attr_type, "VAV-Internal") != 0) //不是VAV内部属性
    {
        temp->output->poutput_wires[0]->usout_data = point->node->poutput_arr[0]->usioput_default_value;
        g_node_func_add_queue_callback_pf(temp->node, temp->output);
		OMIP_LOG_INFO( "acnode_id:%s usout_data:%d", temp->node->acnode_id,   (int)(temp->output->poutput_wires[0]->usout_data));
        return;
    }
    else
    {
        if(strcmp(temp->sensor_type, "AI-T") == 0) //获得面板环境温度
        {
            temp->output->poutput_wires[0]->usout_data =(double)vav_get_panel_env_temp();
			
			vav_set_sys_status_led(vav_get_panel_env_temp_err()? 0 : 1); //如果读取有错误,亮LED灯提示
        }
        else if(strcmp(temp->sensor_type, "AI-TSP") == 0) //获得面板设置温度
        {
            temp->output->poutput_wires[0]->usout_data =(double)vav_get_panel_set_temp();
			vav_set_sys_status_led(vav_get_panel_set_temp_err()? 0 : 1); //如果读取有错误,亮LED灯提示
        }
        else if(strcmp(temp->sensor_type, "AI-P") == 0) //获得压力
        {
            temp->output->poutput_wires[0]->usout_data =vav_get_pressure();
        }
        else if(strcmp(temp->sensor_type, "BI-STATUS") == 0) //获取面板状态
        {
            temp->output->poutput_wires[0]->usout_data = (double)vav_get_panel_status();
			vav_set_sys_status_led(vav_get_panel_status_err()? 0 : 1); //如果读取有错误,亮LED灯提示
        }
        else if(strcmp(temp->sensor_type, "VI-DP") ==0) //获取阀门的开度
        {
            temp->output->poutput_wires[0]->usout_data = vav_get_valve_degree();
        }
        else if(strcmp(temp->sensor_type, "PresentValue") == 0) //获得累计转动角度
        {
            temp->output->poutput_wires[0]->usout_data =(double)vav_get_sum_degree();
        }
        else if(strcmp(temp->sensor_type, "Count") == 0) //获得累计转动次数
        {
            temp->output->poutput_wires[0]->usout_data =(double)vav_get_sum_count();
        }
        else //其他设置位缺省值
        {
            temp->output->poutput_wires[0]->usout_data =point->node->poutput_arr[0]->usioput_default_value;
        }
        g_node_func_add_queue_callback_pf(temp->node, temp->output);
		OMIP_LOG_DEBUG("input acnode_id:%s stype:%s usout_data:%d",
			temp->node->acnode_id, temp->sensor_type, (int)(temp->output->poutput_wires[0]->usout_data));
        vav_set_point_msg(temp->obj_id, temp->output->poutput_wires[0]->usout_data);
    }
}

input_arg_t *get_input_arg_by_node_id(char *node_id) //通过node ID寻找输入节点
{
    input_arg_t *p =g_input_arg_list;
    while(p)
    {
        if(strcmp(node_id,p->node_id) ==0) return p;
        p =p->next;
    }
    return NULL;
}

static int input_point_write_callback(int obj_id, int priority, double value, point_data_t *p)
{
	OMIP_LOG_INFO("write callback obj_id:%d, value:%d, priority:%d, sType:%s\r\n",
			obj_id,(int)(value),priority,  p->node->node_io_attr_ins.acio_attr_sensor_type);
    if(strcmp(p->node->node_io_attr_ins.acio_attr_type, "VAV-Internal") == 0)
    {
        if (strcmp(p->node->node_io_attr_ins.acio_attr_sensor_type, "AI-TSP") == 0 && g_mode != 0x80){
			vav_set_panel_set_temp(value);
		}
        else if (strcmp(p->node->node_io_attr_ins.acio_attr_sensor_type, "BI-STATUS") == 0 && g_mode != 0x80) {
			vav_set_panel_status((int)value);
		}
    }
    return 0;
}

static int ext_node_func_input(flow_node_base_t *node, node_input_wires_t *wires_input, node_output_t *output)
{
    int repeat = (int)node->usrepeat;
	point_data_t *input_point = NULL;
    input_arg_t *arg = get_input_arg_by_node_id(node->acnode_id);
	CENGINE_LOG(CENGINE_LOG_INFO,"input repeat:%d,objid:%d,default:%d.",repeat,arg->obj_id,(int)(node->poutput_arr[0]->usioput_default_value));
    arg->node = node;
    input_point = vav_add_point(arg->obj_id, node, input_point_write_callback); //创建点位
	if(input_point) input_point->priority_arr[15].value = node->poutput_arr[0]->usioput_default_value;
    strcpy(arg->attr_type, node->node_io_attr_ins.acio_attr_type);
    strcpy(arg->sensor_type, node->node_io_attr_ins.acio_attr_sensor_type);
    UINT32 uwRet = LOS_OK;
    UINT16 id;
    uwRet =LOS_SwtmrCreate(repeat*1000,LOS_SWTMR_MODE_PERIOD,input_callback,&id,(UINT32)arg,OS_SWTMR_ROUSES_ALLOW,OS_SWTMR_ALIGN_SENSITIVE);
    if(LOS_OK !=uwRet)	{CENGINE_LOG(CENGINE_LOG_ERR,"create input timer failed!repeat:%d, errorcode:%x.",repeat,uwRet); return NODE_RUN_FAILED;}
    else				{CENGINE_LOG(CENGINE_LOG_INFO,"create input timer success.");}
    uwRet = LOS_SwtmrStart(id);
    if(LOS_OK !=uwRet)	{CENGINE_LOG(CENGINE_LOG_ERR,"start input timer failed."); return NODE_RUN_FAILED;}
    else				{CENGINE_LOG(CENGINE_LOG_INFO,"start input timer success.");}
    arg->timer_id = id;
    return NODE_RUN_WITHOUT_PASS_MSG;
}

static int ext_node_parse_input(flow_node_base_t *node, cJSON *node_data)
{
    cJSON *io_info = cJSON_GetObjectItem(node_data,"ioInfo");
    if(NULL ==io_info) {CENGINE_LOG(CENGINE_LOG_ERR,"ioInfo is null."); return NODE_RUN_FAILED;}
    cJSON *bacnet_obj = cJSON_GetObjectItem(io_info,"bacnetObj");
    if(NULL ==bacnet_obj) {CENGINE_LOG(CENGINE_LOG_ERR,"bacnetObj is null."); return NODE_RUN_FAILED;}
    cJSON *object_identifier = cJSON_GetObjectItem(bacnet_obj,"objectIdentifier");
    if(NULL ==object_identifier) {CENGINE_LOG(CENGINE_LOG_ERR,"objectIdentifier is null."); return NODE_RUN_FAILED;}
    int obj_id = object_identifier->valueint;
    CENGINE_LOG(CENGINE_LOG_INFO, "obj_id:%d.",obj_id);
    input_arg_t *arg = (input_arg_t *)malloc(sizeof(input_arg_t));
    arg->output = (node_output_t *)malloc(sizeof(node_output_t));
    arg->output->poutput_wires[0] = (node_output_wires_t *)malloc(sizeof(node_output_wires_t));
    arg->output->poutput_wires[0]->uwire_index = 0;
    arg->obj_id = obj_id;
    arg->next = NULL;
    arg->node = NULL;
    strcpy(arg->node_id, node->acnode_id);
    //将当前arg放入链表中
    if (g_input_arg_list == NULL)
    {
        g_input_arg_list = arg;
    }
    else
    {
        input_arg_t *temp = g_input_arg_list;
        while(temp && temp->next !=NULL) temp =temp->next;
        temp->next =arg;
    }
    return NODE_RUN_SUCCESS;
}

void ext_node_input_release()
{
    if(g_input_arg_list ==NULL) return;
    input_arg_t *p = g_input_arg_list;
    input_arg_t *q = g_input_arg_list->next;
    LOS_SwtmrStop(p->timer_id);
    LOS_SwtmrDelete(p->timer_id);
    free(p->output->poutput_wires[0]);
    free(p->output);
    free(p);
    while (q)
    {
        p = q;
        q = q->next;
        LOS_SwtmrStop(p->timer_id);
        LOS_SwtmrDelete(p->timer_id);
        free(p->output->poutput_wires[0]);
        free(p->output);
        free(p);
    }
    g_input_arg_list =NULL;
}


static void output_callback(UINT32 arg)
{
    struct output_arg *temp = (struct output_arg *)arg;
    point_data_t *point = vav_get_point_by_id(temp->obj_id);
	flow_node_base_t *node = point->node;
	double out_val = point->priority_arr[point->max_priority -1].value;

	if(point->max_priority == 16) {
		return;
	}
	OMIP_LOG_INFO("output node_id:%s, sType:%s,  priority_arr[%d]:%d \r\n", 
			node->acnode_id, node->node_io_attr_ins.acio_attr_sensor_type, point->max_priority - 1, (int)(out_val));			
    if(strcmp(node->node_io_attr_ins.acio_attr_type, "VAV-Internal") ==0) //是VAV内部节点
    {
        if(strcmp(node->node_io_attr_ins.acio_attr_sensor_type, "VO-DP") ==0) //控制阀门
        	set_target_degree((int)out_val); //设置阀门目标值
        else if(strcmp(node->node_io_attr_ins.acio_attr_sensor_type, "AO-TSP") ==0)
            vav_set_panel_set_temp(out_val);
        else if(strcmp(node->node_io_attr_ins.acio_attr_sensor_type, "BO-STATUS") ==0)
            vav_set_panel_status((int)out_val);
		else
			OMIP_LOG_INFO("unknow set obj_id:%d, stype:%s, value:%d(x1000).",temp->obj_id,node->node_io_attr_ins.acio_attr_sensor_type,(int)(out_val*1000));
    }
}

output_arg_t *get_output_arg_by_node_id(char *node_id) //通过node ID寻找输出节点
{
    output_arg_t *p = g_output_arg_list;
    while(p)
    {
        if(strcmp(node_id, p->node_id)==0) return p;
        p =p->next;
    }
    return NULL;
}

static int output_point_write_callback(int obj_id, int priority, double value, point_data_t *p)
{
	
	OMIP_LOG_INFO("write output obj_id:%d, value:%d(x1000), priority:%d, sType:%s\r\n",
			obj_id,(int)(value),priority,  p->node->node_io_attr_ins.acio_attr_sensor_type);
    if(strcmp(p->node->node_io_attr_ins.acio_attr_type, "VAV-Internal") ==0) //是VAV内部节点
    {
        if(strcmp(p->node->node_io_attr_ins.acio_attr_sensor_type, "VO-DP") ==0)
        {
        	set_target_degree((int)value); //设置阀门目标值
        }
        else if (strcmp(p->node->node_io_attr_ins.acio_attr_sensor_type, "AO-TSP") ==0 && g_mode !=0x80)
        {
            vav_set_panel_set_temp(value);
        }
        else if (strcmp(p->node->node_io_attr_ins.acio_attr_sensor_type, "BO-STATUS") ==0 && g_mode !=0x80)
        {
            vav_set_panel_status((int)value);
        }
		else
		{
			CENGINE_LOG(CENGINE_LOG_WARNING,"[%s:%d]unknow set obj_id:%d, stype:%s, value:%d(x1000).",__FUNCTION__,__LINE__,obj_id,p->node->node_io_attr_ins.acio_attr_sensor_type,(int)(value*1000));
		}
    }
    return 0;
}

static int ext_node_func_output(flow_node_base_t *node, node_input_wires_t *wires_input, node_output_t *output)
{
    output_arg_t *arg = get_output_arg_by_node_id(node->acnode_id);
    point_data_t *point = vav_get_point_by_id(arg->obj_id);
    if (point == NULL) //点位不存在的情况下创建点位
    {
		osal_task_sleep(50);
		point = vav_add_point(arg->obj_id, node, output_point_write_callback); //创建点位
		if(point) point->priority_arr[15].value = node->pinput_arr[0]->usioput_default_value;
        if (strcmp(node->node_io_attr_ins.acio_attr_sensor_type, "VO-DP") ==0)
        {
            UINT32 uwRet = LOS_OK;
            TSK_INIT_PARAM_S task_init_param;
            task_init_param.usTaskPrio = 20;
            task_init_param.pcName = "motor_task";
            task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)motor_task;
            task_init_param.uwStackSize = 0x400;
            uwRet = LOS_TaskCreate(&motor_task_id, &task_init_param); //开启阀门开度设定线程
            if(LOS_OK !=uwRet)	{
				OMIP_LOG_ERROR( "create motor task failed .");
            }
            else {
				OMIP_LOG_INFO( "create motor task success .");
			}
			OMIP_LOG_INFO( "priority_arr[%d]:%d", point->max_priority-1, (int)(point->priority_arr[point->max_priority-1].value));
        }
    }
	
	point->priority_arr[15].value =node->pinput_arr[0]->usioput_default_value;
	arg->cnt =(arg->cnt >30000? 2 : (arg->cnt+1));
	if(arg->cnt > 1)
	{
		point->priority_arr[15].value = wires_input->usin_data;
		if(arg->timer_id != (UINT16)-1)
		{
			LOS_SwtmrStop(arg->timer_id);
			LOS_SwtmrDelete(arg->timer_id);
			arg->timer_id = (UINT16)-1;
		}
	    double out_val =point->priority_arr[point->max_priority - 1].value;
		OMIP_LOG_DEBUG("cengine node_id:%s, sType:%s,  priority_arr[%d]:%d \r\n", 
			node->acnode_id, node->node_io_attr_ins.acio_attr_sensor_type, point->max_priority - 1, (int)(out_val));
	    if(strcmp(node->node_io_attr_ins.acio_attr_type, "VAV-Internal") ==0) //是VAV内部节点
		{
			if (strcmp(node->node_io_attr_ins.acio_attr_sensor_type, "VO-DP") ==0) { //是控制阀门
				set_target_degree((int)out_val); //设置阀门目标值
			}
			else if (strcmp(node->node_io_attr_ins.acio_attr_sensor_type, "AO-TSP") ==0) {
				vav_set_panel_set_temp(out_val); //设置面板温度
			}
			else if (strcmp(node->node_io_attr_ins.acio_attr_sensor_type, "BO-STATUS") ==0) {
				vav_set_panel_status((int)out_val); //设置面板状态
			}
			else {
				OMIP_LOG_DEBUG("unknow set obj_id:%d, stype:%s, value:%d(x1000)\r\n",
					 arg->obj_id,node->node_io_attr_ins.acio_attr_sensor_type,(int)(out_val*1000));
			}
		}
	}
	else
	{
		int repeat =5;
	    UINT32 uwRet =LOS_OK;
	    UINT16 id = 0;
		osal_task_sleep(50);
		OMIP_LOG_INFO("obj_id:%d, value:%d(x1000)\r\n",arg->obj_id,(int)(point->priority_arr[15].value*1000));
	    uwRet =LOS_SwtmrCreate(repeat*1000,LOS_SWTMR_MODE_PERIOD,output_callback,&id,(UINT32)arg,OS_SWTMR_ROUSES_ALLOW,OS_SWTMR_ALIGN_SENSITIVE);
	    if (LOS_OK !=uwRet)	{
			OMIP_LOG_INFO("create output timer failed .error code is %x.",uwRet); 
			return NODE_RUN_FAILED;
		}
	    else {
			OMIP_LOG_INFO("create output timer success .");
		}
		
		osal_task_sleep(50);
		uwRet =LOS_SwtmrStart(id);
	    if(LOS_OK != uwRet)	{
			OMIP_LOG_INFO( "start output timer failed ."); 
			return NODE_RUN_FAILED;
		}
	    else {
			OMIP_LOG_INFO( "start output timer success .");
		}
		arg->timer_id =id;
	}
    return NODE_RUN_SUCCESS;
}

static int ext_node_parse_output(flow_node_base_t *node, cJSON *node_data)
{
    cJSON *io_info =cJSON_GetObjectItem(node_data, "ioInfo");
    if(NULL ==io_info)	{CENGINE_LOG(CENGINE_LOG_ERR,"ioInfo is null."); return NODE_RUN_FAILED;}
    cJSON *bacnet_obj =cJSON_GetObjectItem(io_info, "bacnetObj");
    if(NULL ==bacnet_obj) {CENGINE_LOG(CENGINE_LOG_ERR,"bacnetobj is null."); return NODE_RUN_FAILED;}
    cJSON *object_identifier =cJSON_GetObjectItem(bacnet_obj,"objectIdentifier");
    if(NULL ==object_identifier) {CENGINE_LOG(CENGINE_LOG_ERR,"objectIdentifier is null."); return NODE_RUN_FAILED;}
    int obj_id = object_identifier->valueint;
    output_arg_t *arg = (output_arg_t *)malloc(sizeof(output_arg_t));
    arg->obj_id = obj_id;
	arg->timer_id = (UINT16)-1;
	arg->cnt = 0;
    arg->next = NULL;
    strcpy(arg->node_id, node->acnode_id);
#if 0
	cJSON *attr = cJSON_GetObjectItem(node_data, "inputArr");
	if(attr)
	{
		cJSON *item = cJSON_GetArrayItem(attr, 0);
		if(item)
		{
			cJSON *p = cJSON_GetObjectItem(item,"d");
			if(p) CENGINE_LOG(CENGINE_LOG_WARNING, "valueint:%d",p->valueint);
		}
	}
#endif
	CENGINE_LOG(CENGINE_LOG_WARNING, "obj_id:%d.node_id:%s",arg->obj_id,arg->node_id);
    //将当前arg放入链表中
    if(g_output_arg_list ==NULL)
    {
        g_output_arg_list =arg;
    }
    else
    {
        output_arg_t *temp =g_output_arg_list;
        while (temp && temp->next !=NULL) temp =temp->next;
        temp->next = arg;
    }
    return NODE_RUN_SUCCESS;
}

void ext_node_output_release() //外部输出节点释放
{
    if(motor_task_id) //删除电机线程
    {
        if(LOS_OK!=LOS_TaskDelete(motor_task_id)) {CENGINE_LOG(CENGINE_LOG_ERR, "TaskLo delete failed .\n"); return;}
		CENGINE_LOG(CENGINE_LOG_WARNING, "TaskLo delete succ .\n");
        motor_task_id =0;
    }
    if(g_output_arg_list ==NULL) return;
    output_arg_t *p =g_output_arg_list;
	if(p->timer_id !=(UINT16)-1) {LOS_SwtmrStop(p->timer_id); LOS_SwtmrDelete(p->timer_id);}
    output_arg_t *q =g_output_arg_list->next;
    free(p);
    while (q) //释放链表
    {
        p =q;
		if(p->timer_id !=(UINT16)-1) {LOS_SwtmrStop(p->timer_id); LOS_SwtmrDelete(p->timer_id);}
        q =q->next;
        free(p);
    }
    g_output_arg_list =NULL;
}

void ext_node_func_device_io_init() //注册输入输出节点
{
    cengine_register_ext_node("Input", EXT_NODE_TYPE_INPUT, ext_node_func_input, ext_node_parse_input);
    cengine_register_ext_node("Output", EXT_NODE_TYPE_OUTPUT, ext_node_func_output, ext_node_parse_output);
}

void ext_node_func_device_io_release() //释放输入输出节点
{
    ext_node_input_release();
    ext_node_output_release();
    vav_clear_points();
}
